package com.hfut.wxy.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.hfut.wxy.common.exception.WxyException;
import com.hfut.wxy.common.parent.ParentService;
import com.hfut.wxy.common.response.WxyPage;
import com.hfut.wxy.common.utils.ExchangeUtil;
import com.hfut.wxy.entity.mysql.WxyAppraise;
import com.hfut.wxy.entity.mysql.WxyOrder;
import com.hfut.wxy.entity.mysql.WxyOrderException;
import com.hfut.wxy.entity.mysql.WxyUserInfo;
import com.hfut.wxy.service.IOrderService;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.Date;
import java.util.List;
import java.util.Objects;

@Service
@Transactional(rollbackFor = Exception.class)
public class OrderServiceImpl extends ParentService implements IOrderService {


    @Override
    public Object releaseOrder(WxyOrder wxyOrder) {
        return orderDao.save(wxyOrder);
    }

    @Override
    public boolean receiveOrder(Integer userId, Integer orderId) {
            Integer executorId = orderDao.findExecutorId(orderId);
            if (executorId == null) {
                //乐观锁
                return orderDao.changeReceiverAndSate(userId,orderId) == 1;
            }
            return false;
    }

    @Override
    public Object getOrders(WxyPage page, Integer pickUpAddressId, Float commission, Integer volume) {
        Pageable pageable = WxyPage.getPageable(page, Sort.by(Sort.Order.desc("updateTime")));
        Page<WxyOrder> orderPage;

        if (pickUpAddressId == null){
            orderPage = orderDao.findAllByState(0,pageable);
        } else {
            orderPage = orderDao.findAllByPickUpAddress_IdAndState(pickUpAddressId,0,pageable);
        }
        return WxyPage.build(orderPage, ExchangeUtil.changeListToJSON(orderPage.getContent(),(x, y)->{
            WxyOrder wxyOrder = (WxyOrder) y;
            x.put("id",wxyOrder.getId());
            x.put("pickUpAddress",wxyOrder.getPickUpAddress().getId());
            x.put("address",wxyOrder.getWxyAddress().getAddress());


            //发单人信息
            x.put("creatorId",wxyOrder.getCreator().getId());
            x.put("nickName",wxyOrder.getCreator().getNickName());
            x.put("avatarUrl",wxyOrder.getCreator().getAvatarUrl());

            x.put("payType",wxyOrder.getPayType());
            x.put("comment",wxyOrder.getComment());

            x.put("deliveryTime",wxyOrder.getDeliveryTime());
            x.put("expressCompany",wxyOrder.getExpressCompany());


            x.put("commission",wxyOrder.getCommission());

            x.put("volume",wxyOrder.getVolume());
        }));
    }

    @Override
    public Object getOrdersForOne(WxyPage page, Integer userId, List<Integer> states) {
        Pageable pageable = WxyPage.getPageable(page,Sort.by(Sort.Order.desc("id")));
        Page<WxyOrder> orderList;
        if (CollectionUtils.isEmpty(states)){
            orderList = orderDao.findAllByCreator_Id(userId,pageable);
        } else {
            orderList = orderDao.findAllByCreator_IdAndStateIn(userId, states,pageable);
        }
        return WxyPage.build(orderList,ExchangeUtil.changeListToJSON(orderList.getContent(),(x,y)->{
            WxyOrder order = (WxyOrder) y;
            x.put("id",order.getId());
            x.put("code",order.getCode());
            x.put("expressCompany",order.getExpressCompany());
            x.put("pickUpAddress",order.getPickUpAddress().getId());
            x.put("pickUpPhone",order.getPickUpPhone());
            x.put("deliveryTime",order.getDeliveryTime());
            //接单人数据
            WxyUserInfo executor = order.getExecutor();
            if (executor != null) {
                x.put("executorId", executor.getId());
                x.put("nickName",executor.getNickName());
                x.put("avatarUrl",executor.getAvatarUrl());
            }
            x.put("address",order.getWxyAddress().getAddress());
            x.put("addressId",order.getWxyAddress().getId());
            x.put("payType",order.getPayType());
            x.put("name",order.getName());
            x.put("comment",order.getComment());

            x.put("userPhone",order.getWxyAddress().getPhone());
            x.put("userName",order.getWxyAddress().getName());

            x.put("commission",order.getCommission());
            int state = order.getState();
            x.put("state",state);
            if (state == 4 || state == 5 || state == 6 || state == 7 ){
                WxyOrderException e = orderExceptionDao.findAllByOrderIdOrderByIdDesc(order.getId());
                x.put("description",e.getDescription());
                x.put("isOrderCreator",e.isOrderCreator());
            }
            x.put("volume",order.getVolume());
        }));
    }

    @Override
    public Object companies() {
        JSONArray re = new JSONArray();
        JSONObject info = new JSONObject();
        for (WxyOrder.ExpressCompany value : WxyOrder.ExpressCompany.values()) {
            info.put("name",value.getName());
            info.put("value",value);
            re.add(info);
        }
        return re;
    }

    @Override
    public void removeOrder(Integer orderId) {
        orderDao.deleteById(orderId);
    }

    @Override
    public boolean confirmOrder(Integer orderId) {
        // TODO: 2020/5/7 推送
        WxyOrder wxyOrder = orderDao.getById(orderId);
        wxyOrder.setState(3);
        orderDao.save(wxyOrder);
        //删除聊天记录
        mongoTemplate.remove(new Query(Criteria.where("orderId").is(orderId)),"wxyChat");
        return true;
    }

    @Override
    public Object myExecuteOrder(WxyPage page, Integer userId, List<Integer> states) {
        Pageable pageable = WxyPage.getPageable(page);
        Page<WxyOrder> orderList;
        if (CollectionUtils.isEmpty(states)){
            orderList = orderDao.findAllByExecutor_Id(userId,pageable);
        } else {
            orderList = orderDao.findAllByExecutor_IdAndStateIn(userId, states,pageable);
        }
        return WxyPage.build(orderList, ExchangeUtil.changeListToJSON(orderList.getContent(),(x, y)->{
            WxyOrder order = (WxyOrder) y;
            x.put("id",order.getId());
            x.put("code",order.getCode());
            x.put("expressCompany",order.getExpressCompany());
            x.put("pickUpAddress",order.getPickUpAddress().getId());
            x.put("pickUpPhone",order.getPickUpPhone());

            x.put("name",order.getName());
            x.put("deliveryTime",order.getDeliveryTime());

            x.put("address",order.getWxyAddress().getAddress());
            x.put("userName",order.getWxyAddress().getName());
            x.put("userPhone",order.getWxyAddress().getPhone());
            x.put("creatorId",order.getCreator().getId());
            x.put("nickName",order.getCreator().getNickName());
            x.put("avatarUrl",order.getCreator().getAvatarUrl());
            x.put("payType",order.getPayType());


            x.put("comment",order.getComment());

            x.put("commission",order.getCommission());
            int state = order.getState();
            x.put("state",state);
            if (state == 4 || state == 5 || state == 6 || state == 7 ){
                WxyOrderException e = orderExceptionDao.findAllByOrderIdOrderByIdDesc(order.getId());
                x.put("description",e.getDescription());
                x.put("isOrderCreator",e.isOrderCreator());
            }
            x.put("volume",order.getVolume());
        }));
//        return WxyPage.build(orderList);
    }

    @Override
    public Object finishOrder(Integer orderId) {
        // TODO: 2020/5/7 推送
        WxyOrder wxyOrder = orderDao.getById(orderId);
        wxyOrder.setState(2);
        wxyOrder.setFinishTime(new Date());
        orderDao.save(wxyOrder);
        return true;
    }

    @Override
    public Object cancelOrder(Integer orderId, String description, Integer userId) {
        // TODO: 2020/5/7 推送
//        //撤销订单
//        WxyOrder wxyOrder = orderDao.getById(orderId);
//        //4 订单锁定中
//        wxyOrder.setState(4);
//        orderDao.save(wxyOrder);
        int row = orderDao.cancelOrder(orderId);
        if (row == 0){
            throw WxyException.of("订单已被对方撤销");
        }

        WxyOrderException wxyOrderException = new WxyOrderException();
        wxyOrderException.setDescription(description);
        wxyOrderException.setOrderId(orderId);
        wxyOrderException.setType(1);
        wxyOrderException.setUserId(userId);
        wxyOrderException.setOrderCreator(Objects.equals(userId, orderDao.findCreatorId(orderId)));
        orderExceptionDao.save(wxyOrderException);
        return true;
    }

    @Override
    public Object confirmCancel(Integer orderId, Integer state) {
        //如果发单人，发起了撤销，这个时候发单人只能选择继续派单 1 true，接单人只能选择确认撤销 6 false
        //如果是接单人发起的撤销，接单人只能选择继续派单1 false ，发单人可以选择确认撤销 6 true 和确认撤销并重发订单0 true
        // TODO: 2020/5/7
        WxyOrder wxyOrder = orderDao.getById(orderId);
        wxyOrder.setState(state);
        if (state == 0){
            //订单被发往接单大厅
            wxyOrder.setVersion(1);
        }
        if (state == 1){
            //订单处于被执行状态
            wxyOrder.setVersion(2);
            //删除异常信息,这里记录为没有发生异常
            orderExceptionDao.deleteByOrderIdAndUserId(orderId);
        }
        orderDao.save(wxyOrder);
        if (state == 6){
            mongoTemplate.remove(new Query(Criteria.where("orderId").is(orderId)),"wxyChat");
        }
        return true;
    }

    @Override
    public Object reRelease(Integer orderId) {
        WxyOrder wxyOrder = orderDao.getById(orderId);
        wxyOrder.setVersion(1);
        wxyOrder.setExecutor(null);
        wxyOrder.setState(0);
        orderDao.save(wxyOrder);
        return true;
    }

    @Override
    public boolean appraise(WxyAppraise appraise) {
        appraiseDao.save(appraise);
        return true;
    }
}
